package com.hcloud.libupload.task

import android.util.Log
import com.hcloud.libupload.bean.CompleteReq
import com.hcloud.libupload.bean.PutReq
import com.hcloud.libupload.bean.RegisterReq
import com.hcloud.libupload.bean.StatusReq
import com.hcloud.libupload.callback.ICreateTaskCallback
import com.hcloud.libupload.comom.TaskControl
import com.hcloud.libupload.comom.UploadLib
import com.hcloud.libupload.excetion.UploadError
import com.hcloud.libupload.http.ProgressBody
import com.hcloud.libupload.request.UploadRequest
import com.hcloud.libupload.utils.runOnUi
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.RequestBody.Companion.toRequestBody
import java.io.ByteArrayInputStream
import java.io.File

class ResumeUploadTask(
    uploadRequest: UploadRequest,
    taskControl: TaskControl,
    iCreateTaskCallback: ICreateTaskCallback
) : UploadTask(uploadRequest, taskControl, iCreateTaskCallback) {

    override fun register() {
        super.register()

        if (!File(uploadRequest.filePath).exists()) {
            throw UploadError(UploadError.UPLOAD_ERROR_10000, "the file is not exit !!!")
        }

        if (file.length() == 0L) {
            throw UploadError(UploadError.UPLOAD_ERROR_10003, "the file size is zero error !!!")
        }


        if (uploadRequest.requestId.isBlank()) {
            //register
            val registerReq = RegisterReq(
                cellphone = UploadLib.instance().uploadConfig.phone,
                fileName = file.name,
                parentPath = uploadRequest.serverPath,
                fileSize = file.length(),
                fileLastmod = file.lastModified(),
                fileHash = fileHash,
                partSize = config.partSize.toLong()
            )
            requestTask.register(registerReq) {
                this.uploadRequest.requestId = it.uploadId
                runOnUi {
                    iCreateTaskCallback?.createSuccess(uploadRequest)
                }
                partUpload()
            }
        } else {
            //check upload part


            val statusReq = StatusReq(uploadRequest.requestId)
            requestTask.getPart(statusReq) {
                successPartList.addAll(it.partList)

                runOnUi {
                    iCreateTaskCallback?.createSuccess(uploadRequest)
                }


                partUpload()
            }
        }
    }

    private fun partUpload() {

        val size = (file.length() / config.partSize).toInt()
        val offset = file.length() % config.partSize
        val part = if (offset == 0L) size else size + 1

        this.allPartSize = part

        Log.i(
            "upload--sdk",
            "-----getPart--${allPartSize}-${successPartList.size}"
        )

        if (successPartList.size == allPartSize) {
            if (!checkError()) {
                complete()
            }
        } else {
            for (i in 0 until part) {

                if (successPartList.contains(i.toString())) {
                    if (i == part - 1) {
                        if (offset == 0L) {
                            progress.currentSize += config.partSize
                        } else {
                            progress.currentSize += offset
                        }
                    } else {
                        progress.currentSize += config.partSize
                    }
                    continue
                }

                val partSize =
                    if (i == part - 1) {
                        if (offset == 0L) {
                            config.partSize.toString()
                        } else {
                            offset.toString()
                        }
                    } else {
                        config.partSize.toString()
                    }

                val putReq = PutReq(uploadRequest.requestId, i.toString(), partSize)

                partPool.execute {
                    upload(putReq)
                }

            }
            synchronized(lock) {
                lock.wait()
            }

            if (!checkError()) {
                complete()
            }
        }
    }


    override fun upload(putReq: PutReq) {

        Log.i(
            "upload--sdk",
            "-----upload--count-----${putReq.uploadId} ${putReq.partStart} ${putReq.partSize}"
        )
        try {

            if (uploadRequest.isCancel || uploadError != null) {
                partPool.queue.clear()
                return
            }


            val partArray = file2Body.file2Body(
                file,
                putReq.partStart.toLong() * config.partSize,
                putReq.partSize.toInt()
            )

            val requestBody =
                partArray.toRequestBody("application/octet-stream".toMediaTypeOrNull())

            val progressBody = ProgressBody(
                uploadRequest,
                requestBody,
                progress,
                ByteArrayInputStream(partArray)
            )

            requestTask.putUpload(putReq, progressBody) {
                addSuccess(putReq)
            }
        } catch (t: Throwable) {
            if (uploadError == null) {
                Log.i("upload-sdk", "start task---------part error--${t.message}-----")
                uploadError = t
                partPool.queue.clear()
                notifyLock()
            }
        }
    }


    @Synchronized private  fun  addSuccess(putReq: PutReq){
        successPartList.add(putReq.partStart)
        if (successPartList.size == allPartSize) {
            notifyLock()
        }
    }


    private fun notifyLock() {
        synchronized(lock) {
            lock.notify()
        }
    }


    override fun complete() {
        val completeReq = CompleteReq(uploadRequest.requestId)
        requestTask.complete(completeReq) {
            release()
            Thread.sleep(500)
            runOnUi {
                iProgressCallback?.success(uploadRequest)
            }
        }
    }
}